package com.shareware.common.utils

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.content.pm.SigningInfo
import android.net.Uri
import android.os.Build
import android.os.Looper
import android.os.Process
import android.provider.Settings
import android.telephony.TelephonyManager
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.webkit.WebSettings
import androidx.annotation.ChecksSdkIntAtLeast
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.shareware.common.*
import com.shareware.common.delegate.Preference
import com.shareware.common.listener.Callback
import com.shareware.common.model.EnvironmentType
import com.shareware.common.secure.aes.AesCbc
import java.io.File
import java.io.FileFilter
import java.io.FileInputStream
import java.net.NetworkInterface
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.zip.ZipFile
import kotlin.system.exitProcess

/**
 * desc: 功能描述
 * android.Build.Brand: HUAWEI,HONOR,OPPO,VIVO,XIAOMI,REDMI,SAMSUNG,ONEPLUS,MEIZU,REALME(真我),SMARTISAN,BLACKSHARK(黑鲨),MEITU,NUBIA,
 * LENOVO,NOKIA,SONY,ZTE,GIONEE(金立)，ASUS（华硕）,Hisense(海信)，motorola(摩托罗拉)等等
 * email: mobiledeveloper@qq.com
 */

//记忆上次点击的初始时间
private var lastClickTime: Long = 0
private const val CLICK_TIME_STEP: Long = 800
private val backgroundListeners = ConcurrentHashMap<Callback<Boolean>, Boolean>()

//App是否处于后台状态
@Volatile
var appBackground = true
    set(value) {
        if (field != value) {
            field = value
            backgroundListeners.keys.forEach {
                it.call(value)
            }
        }
    }

/**
 * 注册background监听
 */
fun registerBackgroundListener(listener: Callback<Boolean>) {
    backgroundListeners[listener] = true
}

fun unregisterBackgroundListener(listener: Callback<Boolean>) {
    backgroundListeners.remove(listener)
}

private const val APP_PRIVACY_HAS_GRANT = "app.privacy.grant"
private var privacyHasGrant: Boolean by Preference(APP_PRIVACY_HAS_GRANT, false, PREFERENCE_SETTING)

@Volatile
private var appPrivacyState = privacyHasGrant

/**
 * 应用是否同意隐私协议
 */
fun appPrivacyHasGrant(): Boolean {
    return appPrivacyState
}

/**
 * 应用同意隐私协议
 */
fun appPrivacyGrant() {
    if (appPrivacyState) {
        return
    }
    privacyHasGrant = true
    appPrivacyState = true
    if (deviceOaId.isEmpty()) {
        tryMethodIgnore {
            Class.forName("com.shareware.oaid.OaIdGenerator").newInstance()
        }
    }
}

/**
 * 防止快速点击
 * @return boolean
 */
fun isFastDoubleClick(): Boolean {
    val time = System.currentTimeMillis()
    val step = time - lastClickTime
    if (step in 1 until CLICK_TIME_STEP) {
        return true
    }
    lastClickTime = time
    return false
}

fun isFastDoubleClick(view: View): Boolean {
    try {
        val currentClickTime = System.currentTimeMillis()
        val lastClickTime = view.getTag(R.id.tag_view_onclick_timestamp) as? Long
        if (lastClickTime != null) {
            if (currentClickTime - lastClickTime < CLICK_TIME_STEP) {
                return true
            }
        }
        view.setTag(R.id.tag_view_onclick_timestamp, currentClickTime)
    } catch (ignore: Exception) {
        logStackTrace(DEFAULT, ignore)
    }
    return false
}

fun isFastDoubleClick(any: Any): Boolean {
    try {
        val currentClickTime = System.currentTimeMillis()
        val eventKey = any.hashCode()
        val lastClickTime = ActivityExt.lifecycleCallbacks.eventTimestamp[eventKey]
        if (lastClickTime != null) {
            if (currentClickTime - lastClickTime < CLICK_TIME_STEP) {
                return true
            }
        }
        ActivityExt.lifecycleCallbacks.eventTimestamp[eventKey] = currentClickTime
    } catch (ignore: Exception) {
        logStackTrace(DEFAULT, ignore)
    }
    return false
}

fun checkMainProcess(): Boolean {
    return getCurProcessName() == getContextGlobal().packageName
}

/**
 * @return 是否为主线程
 */
fun checkMainThread(): Boolean {
    return Thread.currentThread() === Looper.getMainLooper().thread
}

/**
 * android O 之前有效，O后仅提供调试，或返回当前应用的service
 * @return 检查service是否存在
 */
fun checkServiceExisted(serviceName: String): Boolean {
    val manager = getContextGlobal().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val serviceList = manager.getRunningServices(Int.MAX_VALUE)
    if (serviceList.isNullOrEmpty()) {
        return false
    }
    serviceList.forEach {
        if (it.service.className == serviceName) {
            return true
        }
    }
    return false
}

/**
 * 获取正在运行的前台服务
 */
fun getRunningServices(foreground: Boolean = true): List<String> {
    val services = ArrayList<String>()
    val manager = getContextGlobal().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val runningServiceInfoList = manager.getRunningServices(Int.MAX_VALUE)
    if (runningServiceInfoList.isNullOrEmpty()) {
        return emptyList()
    }
    for (serviceInfo in runningServiceInfoList) {
        if (serviceInfo.uid != Process.myUid()) {
            continue
        }
        if (serviceInfo.pid != Process.myPid()) {
            continue
        }
        if (foreground) {
            if (serviceInfo.foreground) {
                services.add(serviceInfo.service.className)
            }
        } else {
            services.add(serviceInfo.service.className)
        }
    }
    return services
}

/**
 * 获取当前进程的name
 *
 * @return name
 */
@SuppressLint("PrivateApi")
fun getCurProcessName(): String {
    val processName: String? = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
        Application.getProcessName()
    } else {
        reflectPublicStaticMethod(
            "android.app.ActivityThread", "currentProcessName"
        ) as? String
    }
    if (!processName.isNullOrEmpty()) {
        return processName
    }
    val myPid = Process.myPid()
    try {
        val manager =
            getContextGlobal().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        for (appProcess in manager.runningAppProcesses) {
            if (appProcess.pid == myPid) {
                return appProcess.processName
            }
        }
    } catch (e: Exception) {
        logStackTrace("getCurProcessName", e)
    }
    val byteArray = ByteArray(128)
    var fileInputStream: FileInputStream? = null
    try {
        fileInputStream = FileInputStream("/proc/$myPid/cmdline")
        var len = fileInputStream.read(byteArray)
        if (len > 0) {
            for (i in 0 until len) { // lots of '0' in tail , remove them
                if (byteArray[i] <= 0) {
                    len = i
                    break
                }
            }
            return String(byteArray, 0, len, Charsets.UTF_8)
        }
    } catch (e: Exception) {
        logStackTrace("getCurProcessName", e)
    } finally {
        try {
            fileInputStream?.close()
        } catch (e: Exception) {
            logStackTrace("getCurProcessName", e)
        }
    }
    return ""
}

/**
 * @return 图片缓存路径
 */
fun getImgCachePath(): String {
    return File(rootPath + File.separator + "imageCache").createFile(false).absolutePath
}

/**
 * @return 下载路径
 */
fun getDownloadPath(): String {
    return File(rootPath + File.separator + "download").createFile(false).absolutePath
}

private var logRootPath = ""

/**
 * @return 日志路径
 */
@JvmOverloads
fun getLogPath(logRoot: String = ""): String {
    if (logRootPath.isEmpty()) {
        logRootPath = logRoot.removeSuffix(File.separator)
    }
    return if (logRootPath.isNotEmpty() && ContextCompat.checkSelfPermission(
            getContextGlobal(),
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED
    ) {
        File(logRootPath + File.separator + "full_log").createFile(false).absolutePath
    } else {
        File(rootPath + File.separator + "full_log").createFile(false).absolutePath
    }
}

/**
 * @return crash路径
 */
fun getCrashPath(): String {
    return File(rootPath + File.separator + "crash_log").createFile(false).absolutePath
}

/**
 * 根路径
 */
val rootPath: String = getContextGlobal().getExternalFilesDir("")?.absolutePath
    ?: getContextGlobal().filesDir.absolutePath

/**
 * 获取已安装应用市场包名列表
 *
 * @return 已安装的应用市场包名列表
 */
fun Context.queryInstalledMarketPkg(): List<String> {
    val intent = Intent()
    intent.action = Intent.ACTION_MAIN
    intent.addCategory(Intent.CATEGORY_APP_MARKET)
    val resolveInfo = this.packageManager.queryIntentActivities(intent, 0)
    return resolveInfo.indices.filter { resolveInfo[it].activityInfo.packageName.isNotEmpty() }
        .map {
            resolveInfo[it].activityInfo.packageName
        }
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R)
fun atLeastR(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.Q)
fun atLeastQ(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
fun atLeastP(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
fun atLeastO(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
fun atLeastN(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.M)
fun atLeastM(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
}

/**
 * 获取已安装应用的包名列表
 *
 * @return 所有包名列表
 */
fun Context.getInstalledPkg(): List<String> {
    val resolveInfo = this.packageManager.getInstalledPackages(0)
    return resolveInfo.indices.filter { resolveInfo[it].applicationInfo.packageName.isNotEmpty() }
        .map {
            resolveInfo[it].applicationInfo.packageName
        }
}

/**
 * 判断app是否安装
 *
 * @return 是否安装
 */
fun Context.isAppInstalled(packageName: String): Boolean {
    val pm = this.packageManager
    return try {
        pm.getApplicationInfo(packageName, 0).enabled
    } catch (e: PackageManager.NameNotFoundException) {
        false
    }
}

/**
 * 启动到app详情界面
 *
 * @param appPkg    App的包名
 * @param marketPkg 应用商店包名 ,如果为""则由系统弹出应用商店列表供用户选择,
 * 否则调转到目标市场的应用详情界面，某些应用商店可能会失败
 */
fun Context.launchAppDetail(appPkg: String, marketPkg: String) {
    val intent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$appPkg"))
    intent.setPackage(marketPkg)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    this.startActivity(intent)
}

/**
 * 安装Apk
 *
 * @param file .apk文件
 */
fun Context.installApk(file: File) {
    val intent = Intent()
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    intent.action = Intent.ACTION_VIEW
    val uri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        FileProvider.getUriForFile(
            this, this.packageName + ".fileProvider", file
        )
    } else {
        file.fileUri()
    }
    intent.setDataAndType(
        uri,
        "application/vnd.android.package-archive"
    )
    this.startActivity(intent)
}

/**
 * @param packageName pkg
 * 卸载apk
 */
fun Context.uninstallApk(packageName: String) {
    val uri = Uri.parse("package:$packageName")
    val intent = Intent(Intent.ACTION_DELETE, uri)
    this.startActivity(intent)
}

/**
 * 获取自身APP的MD5值
 *
 * @return MD5值
 */
@SuppressLint("PackageManagerGetSignatures")
fun getAppMd5(): String {
    return getContextGlobal().packageManager.getPackageInfo(
        getContextGlobal().packageName,
        PackageManager.GET_SIGNATURES
    ).signatures[0].toByteArray().encodeMd5()
}

/**
 * 获取App versionCode
 *
 * @return versionCode
 */
fun getAppVersionCode(): Long {
    val packageInfo = try {
        getContextGlobal().packageManager.getPackageInfo(getContextGlobal().packageName, 0)
    } catch (ignore: Exception) {
        return 0
    }
    return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
        packageInfo.longVersionCode
    } else {
        packageInfo.versionCode.toLong()
    }
}

/**
 * 获取App versionName
 *
 * @return versionName
 */
fun getAppVersionName(): String {
    val packageInfo = try {
        getContextGlobal().packageManager.getPackageInfo(getContextGlobal().packageName, 0)
    } catch (ignore: Exception) {
        return ""
    }
    return packageInfo.versionName
}

/**
 * 获取App 名称
 */
fun getAppName(): String {
    return try {
        val packageManager = getContextGlobal().packageManager
        val applicationInfo = packageManager
            .getApplicationInfo(getContextGlobal().packageName, PackageManager.GET_META_DATA)
        applicationInfo.loadLabel(packageManager).toString()
    } catch (ignore: Throwable) {
        ""
    }
}

/**
 * @return 运行商名称
 */
fun getSimOperatorName(): String {
    val telephonyManager: TelephonyManager? =
        getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
    var operatorName = "未知运行商"
    telephonyManager?.simOperator?.let {
        val name = getSimOperatorName(it)
        if (name.isNotEmpty()) {
            return name
        } else {
            telephonyManager.simOperatorName?.let { simName ->
                operatorName = simName
            }
        }
    }
    telephonyManager?.networkOperator?.let {
        val name = getSimOperatorName(it)
        if (name.isNotEmpty()) {
            return name
        } else {
            telephonyManager.networkOperatorName?.let { simName ->
                operatorName = simName
            }
        }
    }
    return operatorName
}

private fun getSimOperatorName(name: String): String {
    return when (name) {
        "46001",
        "46006",
        "46009",
        -> {
            "中国联通"
        }

        "46000",
        "46002",
        "46004",
        "46007",
        "46020",
        -> {
            "中国移动"
        }

        "46003",
        "46005",
        "46011",
        -> {
            "中国电信"
        }

        else -> ""
    }
}

private const val DEVICE_ME_ID = "device.me.id"
private var deviceMeId: String by Preference(DEVICE_ME_ID, "", PREFERENCE_SETTING)

/**
 * 获取卡一MeId
 */
fun getMeid(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (deviceMeId.isEmpty()) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P ||
            ContextCompat.checkSelfPermission(
                getContextGlobal(),
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return ""
        }
        val telephonyManager =
            getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
                ?: return ""
        val meId = reflectPublicMethod(telephonyManager, "getMeid") as? String
        if (!meId.isNullOrEmpty()) {
            deviceMeId = meId
        }
    }
    return deviceMeId
}


private const val DEVICE_ME_ASSISTANT = "device.me.assistant"
private var deviceMeIdAssistant: String by Preference(DEVICE_ME_ASSISTANT, "", PREFERENCE_SETTING)

/**
 * 获取卡二MEID
 */
fun getMeidAssistant(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (deviceMeIdAssistant.isEmpty()) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P ||
            ContextCompat.checkSelfPermission(
                getContextGlobal(),
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return ""
        }
        val telephonyManager =
            getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
                ?: return ""
        val meIdAssistant = reflectPublicMethod(
            telephonyManager, "getMeid", arrayOf(Int::class.java), arrayOf(NUMBER_ONE)
        ) as? String
        if (!meIdAssistant.isNullOrEmpty()) {
            deviceMeIdAssistant = meIdAssistant
        }
    }
    return deviceMeIdAssistant
}

/**
 * @return 手机号
 */
@SuppressLint("HardwareIds")
fun getPhoneNumber(): String {
    if (ContextCompat.checkSelfPermission(
            getContextGlobal(),
            Manifest.permission.READ_PHONE_STATE
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        return ""
    }
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
        if (ContextCompat.checkSelfPermission(
                getContextGlobal(),
                Manifest.permission.READ_PHONE_NUMBERS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return ""
        }
        if (ContextCompat.checkSelfPermission(
                getContextGlobal(),
                Manifest.permission.READ_SMS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return ""
        }
    }
    val telephonyManager: TelephonyManager? =
        getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
    return try {
        telephonyManager?.line1Number ?: ""
    } catch (ex: Exception) {
        log(DEFAULT, ex.message ?: "")
        ""
    }
}

/**
 * @return 设备软件版本
 */
fun getDeviceSoftwareVersion(): String? {
    val telephonyManager: TelephonyManager? =
        getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
    return if (ContextCompat.checkSelfPermission(
            getContextGlobal(),
            Manifest.permission.READ_PHONE_STATE
        ) == PackageManager.PERMISSION_GRANTED
    ) {
        try {
            telephonyManager?.deviceSoftwareVersion
        } catch (ex: Exception) {
            log(DEFAULT, ex.message ?: "")
            UNKNOWN
        }
    } else {
        log(DEFAULT, PERMISSION_DENIED)
        UNKNOWN
    }
}

/**
 * 获取SIM卡状态
 * SIM_STATE_UNKNOWN
 * SIM_STATE_ABSENT
 * SIM_STATE_PERM_DISABLED
 * SIM_STATE_CARD_IO_ERROR
 * 以上四个为当前sim卡不可用
 *
 * 5.0系统开始支持双卡，老版本使用getSimStateGemini，不建议获取
 * @param slotIndex 卡槽
 */
fun getSimState(slotIndex: Int): Int {
    val telephonyManager: TelephonyManager =
        getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
            ?: return TelephonyManager.SIM_STATE_UNKNOWN
    return try {
        return reflectPublicMethod(
            telephonyManager,
            "getSimState",
            arrayOf(Int::class.java),
            arrayOf(slotIndex)
        ) as Int
    } catch (ex: Exception) {
        telephonyManager.simState
    }
}

private const val DEVICE_ID = "device.id2"
private var deviceIdentification: String by Preference(DEVICE_ID, "", PREFERENCE_SETTING)

/**
 * 获取设备唯一Id
 */
@SuppressLint("HardwareIds")
fun getDeviceId(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (deviceIdentification.isEmpty()) {
        var address = getImei()
        if (address.isEmpty()) {
            address = getAddressMac()
        }
        if (address.isEmpty() || MAC_UNKNOWN_ADDRESS == address) {
            address = UUID.randomUUID().toString()
        }
        deviceIdentification = address.encodeMd5()
    }
    return deviceIdentification
}

private const val DEVICE_IMEI = "device.imei"
private var phoneImei: String by Preference(DEVICE_IMEI, "", PREFERENCE_SETTING)

/**
 * 标识了 GSM 和 UMTS网络里的唯一一个手机.
 */
@SuppressLint("HardwareIds", "MissingPermission")
fun getImei(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (phoneImei.isEmpty()) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P ||
            ContextCompat.checkSelfPermission(
                getContextGlobal(),
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return ""
        }
        val telephonyManager =
            getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
                ?: return ""
        val imei =
            reflectPublicMethod(telephonyManager, "getImei") as? String
                ?: reflectPublicMethod(telephonyManager, "getDeviceId") as? String
                ?: telephonyManager.deviceId ?: ""
        if (imei.isNotEmpty()) {
            phoneImei = imei
        }
    }
    return phoneImei
}

private const val DEVICE_IMEI_ASSISTANT = "device.imei.assistant"
private var phoneImeiAssistant: String by Preference(DEVICE_IMEI_ASSISTANT, "", PREFERENCE_SETTING)

@SuppressLint("HardwareIds", "MissingPermission")
fun getImeiAssistant(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (phoneImeiAssistant.isEmpty()) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P ||
            ContextCompat.checkSelfPermission(
                getContextGlobal(),
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return ""
        }
        val telephonyManager =
            getContextGlobal().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
                ?: return ""
        val imeiAssistant = reflectPublicMethod(
            telephonyManager, "getImei", arrayOf(Int::class.java), arrayOf(NUMBER_ONE)
        ) as? String ?: reflectPublicMethod(
            telephonyManager, "getDeviceId", arrayOf(Int::class.java), arrayOf(NUMBER_ONE)
        ) as? String ?: telephonyManager.deviceId ?: getImei()
        if (imeiAssistant.isNotEmpty()) {
            phoneImeiAssistant = imeiAssistant
        }
    }
    return phoneImeiAssistant
}

private const val DEVICE_MAC = "device.mac"
private var deviceMac: String by Preference(DEVICE_MAC, "", PREFERENCE_SETTING)
private var macAddress: String = AesCbc.decrypt(deviceMac, "7a68616f64642677616e6779756a6965")

/**
 * 获取Mac地址
 */
@SuppressLint("HardwareIds")
fun getAddressMac(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (macAddress.isEmpty()) {
        var address = ""
        try {
            val interfaces: List<NetworkInterface> =
                Collections.list(NetworkInterface.getNetworkInterfaces())
            for (netInterface in interfaces) {
                if (!netInterface.name.equals("wlan0", true)) continue
                val mac: ByteArray = netInterface.hardwareAddress ?: break
                val buf = StringBuilder()
                mac.forEach {
                    buf.append(String.format("%02X:", it))
                }
                if (buf.isNotEmpty()) buf.deleteCharAt(buf.length - 1)
                address = buf.toString().ifEmpty {
                    MAC_UNKNOWN_ADDRESS
                }
                break
            }
        } catch (ignore: Exception) {
        }
        if (address.isNotEmpty()) {
            deviceMac = AesCbc.encrypt(address, "7a68616f64642677616e6779756a6965")
            macAddress = address
        }
    }
    return macAddress
}

fun Context.openAppSetting() {
    val intent =
        Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName"))
    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
    startActivity(intent)
}

fun Context.toggleSoftInput() {
    (this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
        .toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
}

fun View.showSoftInput(): Boolean {
    return (this.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
        .showSoftInput(this, InputMethodManager.SHOW_FORCED)
}

fun Activity.showSoftInput(): Boolean {
    return this.currentFocus?.showSoftInput() ?: false
}

fun View.hideSoftInput(): Boolean {
    return (this.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
        .hideSoftInputFromWindow(windowToken, 0)
}

fun Activity.hideSoftInput(): Boolean {
    return this.currentFocus?.hideSoftInput() ?: false
}

private const val USER_AGENT = "user.agent"
private var userAgent: String by Preference(USER_AGENT, "", PREFERENCE_SETTING)

/**
 * @return 获取系统UA
 */
fun getAppUserAgent(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (userAgent.isEmpty()) {
        userAgent = try {
            WebSettings.getDefaultUserAgent(getContextGlobal())
        } catch (ignore: Exception) {
            ""
        }
    }
    return userAgent
}

/**
 * @return 获取App当前环境
 */
fun appEnvironment(): EnvironmentType {
    return try {
        EnvironmentType.valueOf(appEnvironment)
    } catch (ex: Exception) {
        EnvironmentType.PRODUCT
    }
}

/**
 * 当前是否是jenkins环境
 */
fun appJenkinsJob(): Boolean {
    return appJenkinsJob
}

/**
 * 重启应用
 */
fun restartApp() {
    val packageName: String = getContextGlobal().packageName
    val defaultIntent: Intent =
        getContextGlobal().packageManager.getLaunchIntentForPackage(packageName)
            ?: return
    defaultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
    ContextCompat.startActivity(getContextGlobal(), defaultIntent, null)
    exitProcess(0)
}

/**
 * 获取设备内存大小
 */
fun getMemoryTotalSize(): Long {
    val activityManager =
        getContextGlobal().getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
            ?: return 0
    val memoryInfo = ActivityManager.MemoryInfo()
    return try {
        activityManager.getMemoryInfo(memoryInfo)
        memoryInfo.totalMem
    } catch (ignore: Throwable) {
        0
    }
}

/**
 * 获取设备空闲内存大小
 */
fun getMemoryAvailSize(): Long {
    val activityManager =
        getContextGlobal().getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
            ?: return 0
    val memoryInfo = ActivityManager.MemoryInfo()
    return try {
        activityManager.getMemoryInfo(memoryInfo)
        memoryInfo.availMem
    } catch (ignore: Throwable) {
        0
    }
}

/**
 * 获取CPU核数
 */
fun getCpuNumCores(): Int {
    return try {
        val dir = File("/sys/devices/system/cpu/")
        dir.listFiles(FileFilter {
            Regex("cpu[0-9]+").matches(it.name)
        })?.size ?: 0
    } catch (ignore: Throwable) {
        0
    }
}


private const val ANDROID_ID = "device.android"
private var deviceAndroidId: String by Preference(ANDROID_ID, "", PREFERENCE_SETTING)

/**
 * 获取AndroidId
 */
fun getAndroidID(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (deviceAndroidId.isEmpty()) {
        var androidId = try {
            Settings.System.getString(
                getContextGlobal().contentResolver, Settings.Secure.ANDROID_ID
            ) ?: ""
        } catch (ignore: Exception) {
            ""
        }
        if ("9774d56d682e549c" == androidId) {
            androidId = ""
        }
        if (androidId.isNotEmpty()) {
            deviceAndroidId = androidId
        }
    }
    return deviceAndroidId
}

private const val OA_ID = "device.oa.id"
private var deviceOaId: String by Preference(OA_ID, "", PREFERENCE_SETTING)

/**
 * 获取广告ID
 */
fun getOaId(): String {
    if (!appPrivacyHasGrant()) {
        log(DEFAULT, "privacy has not grant")
        return ""
    }
    if (deviceOaId.isEmpty()) {
        deviceOaId = getPreferences(PREFERENCE_SETTING).getString(OA_ID, "") ?: ""
    }
    return deviceOaId
}

@SuppressLint("PrivateApi")
fun getAppChannel(): String {
    return reflectPublicStaticMethod(
        "com.android.channel.ChannelUtil", "getChannel",
        arrayOf(Context::class.java),
        arrayOf(getContextGlobal())
    ) as? String ?: ""
}

/**
 * 获取应用是否首次安装
 */
fun isAppFirstInstall(): Boolean {
    return ActivityExt.appFirstInstall
}

/**
 * 获取系统支持的ABI
 */
fun getSystemABI(): String {
    return Build.SUPPORTED_ABIS.joinToString(",")
}

/**
 * 获取当前App的ABI
 */
fun getAppAbi(): String {
    return reflectPublicField(getContextGlobal().applicationInfo, "primaryCpuAbi").toString()
}

/**
 * 获取当前App支持的ABI
 */
fun getAppAbiSet(): Set<String> {
    val applicationInfo = getContextGlobal().applicationInfo
    val abiSet = hashSetOf<String>()
    tryMethodIgnore {
        ZipFile(applicationInfo.sourceDir).use {
            val entries = it.entries()
            while (entries.hasMoreElements()) {
                val elementName = entries.nextElement().name
                if (elementName.startsWith("lib/")) {
                    when {
                        elementName.contains("arm64-v8a") -> {
                            abiSet.add("arm64-v8a")
                        }

                        elementName.contains("armeabi-v7a") -> {
                            abiSet.add("armeabi-v7a")
                        }

                        elementName.contains("armeabi") -> {
                            abiSet.add("armeabi")
                        }
                    }
                }
                if (abiSet.size == 3) {
                    break
                }
            }
        }
    }
    return abiSet
}

/**
 * 获取.so的文件信息
 */
fun getAppSoInfo(
): Map<String, Long> {
    val nativePath = getContextGlobal().applicationInfo.nativeLibraryDir
    if (nativePath != null) {
        File(nativePath).listFiles()?.let { files ->
            return files.asSequence().distinctBy { it.name }.map {
                Pair(it.name, it.length())
            }.toMap()
        }
    }
    return emptyMap()
}

private val dependenciesInfo = hashMapOf<String, Long>()

private fun initDependenciesInfo() {
}

/**
 * 获取三方依赖的文件信息
 */
fun getAppDependenciesInfo(): Map<String, Long> {
    if (dependenciesInfo.isEmpty()) {
        initDependenciesInfo()
    }
    return dependenciesInfo
}

fun getAppSignaturesSHA1(packageName: String): String {
    return getAppSignaturesHash(packageName, "SHA1")
}

fun getAppSignaturesSHA256(packageName: String): String {
    return getAppSignaturesHash(packageName, "SHA256")
}

fun getAppSignaturesMD5(packageName: String): String {
    return getAppSignaturesHash(packageName, "MD5")
}

/**
 * 经验证signatures[0].toByteArray()等价于CertificateFactory.getInstance("X.509").generateCertificate(ByteArrayInputStream(signatures[0].toByteArray())).encoded
 */
private fun getAppSignaturesHash(packageName: String, algorithm: String): String {
    val signatures: Array<Signature>? = getAppSignatures(packageName)
    if (signatures.isNullOrEmpty()) {
        return ""
    }
    return SecretUtil.shaEncrypt(signatures[0].toByteArray(), algorithm)
}

@SuppressLint("PackageManagerGetSignatures")
fun getAppSignatures(packageName: String): Array<Signature>? {
    return if (packageName.isEmpty()) null else try {
        val pm: PackageManager = getContextGlobal().packageManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES)
                ?: return null
            val signingInfo: SigningInfo = pi.signingInfo
            if (signingInfo.hasMultipleSigners()) {
                signingInfo.apkContentsSigners
            } else {
                signingInfo.signingCertificateHistory
            }
        } else {
            val pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES) ?: return null
            pi.signatures
        }
    } catch (e: PackageManager.NameNotFoundException) {
        e.printStackTrace()
        null
    }
}